﻿using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RestSharp;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace DBMC_Core
{
    public class LauncherCore
    {
        public static readonly DateTime startTime = DateTime.Now;
        public string ConfigFile => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DBMC.json");
        public static string Data => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data");
        public static string DeLog => Path.Combine(Data, "logs");
        public bool ConfigFileExists => File.Exists(ConfigFile);
        public bool DeLogExists
        {
            get
            {
                if (!Directory.Exists(DeLog))
                {
                    Directory.CreateDirectory(DeLog);
                    return true;
                }
                else
                {
                    return true;
                }
            }
        }
        public long GenerateTimeStamp => new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
        public bool HasMoreThan24HoursPassed(long timestamp)
        {
            // 转换时间戳为 DateTime
            DateTime specifiedTime = DateTimeOffset.FromUnixTimeSeconds(timestamp).UtcDateTime;

            // 获取当前 UTC 时间
            DateTime currentTime = DateTime.UtcNow;

            // 计算时间差
            TimeSpan difference = currentTime - specifiedTime;

            // 如果过去的时间超过24小时，则返回 true
            return difference.TotalHours > 24;
        }
        public static void WriteGameLog(string message)
        {
            string logDirectory = Path.Combine(DeLog, "Game");
            string logFile = Path.Combine(logDirectory, $"{startTime:yyyy-MM-dd_HH-mm-ss}.log");
            if (!Directory.Exists(logDirectory))
            {
                Directory.CreateDirectory(logDirectory);
            }

            using (StreamWriter writer = new StreamWriter(logFile, true))
            {
                writer.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}");
            }
        }
        public static void WriteLog(string message)
        {
            string logDirectory = Path.Combine(DeLog, "App");
            string logFile = Path.Combine(logDirectory, $"{startTime:yyyy-MM-dd_HH-mm-ss}.log");
            if (!Directory.Exists(logDirectory))
            {
                Directory.CreateDirectory(logDirectory);
            }
            using (StreamWriter writer = new StreamWriter(logFile, true))
            {
                writer.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}");
            }
        }
    }

    public class LauncherTools
    {
        public static string ToolsPath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data", "tools");

        public static string SavePath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data", "saves");

        public static string SaveBackupPath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data", "saves", "backup");

        public class NBTExplorer
        {
            public static Process process = null;
            public static string NBTExplorerPath => Path.Combine(ToolsPath, "NBTExplorer");
            public static string NBTExplorerExe => Path.Combine(NBTExplorerPath, "NBTExplorer.exe");
            public static bool Use(string LevelPath)
            {
                ProcessStartInfo startInfo = new ProcessStartInfo
                {
                    FileName = NBTExplorerExe,
                    Arguments = "\"" + LevelPath + "\"", // 为路径添加双引号，以防路径中有空格
                    UseShellExecute = false
                };

                try
                {
                    process = Process.Start(startInfo); // 这里不使用using, 因为我们想保持进程开启
                    return process != null; // 返回进程是否启动成功
                }
                catch (Exception e)
                {
                    Console.WriteLine($"启动失败: {e.Message}");
                    return false;
                }
            }
            public static bool Close(bool Kill = false)
            {
                if (process == null) return false; // 如果进程不存在，无法关闭

                if (!process.HasExited) // 检查进程是否还在运行
                {
                    if (Kill)
                    {
                        process.Kill(); // 强制关闭进程
                    }
                    else
                    {
                        if (!process.CloseMainWindow()) // 尝试正常关闭进程
                        {
                            process.Kill(); // 如果无法正常关闭，则执行强制关闭
                        }
                    }
                }

                process.WaitForExit(); // 等待进程退出
                process.Dispose(); // 释放进程资源
                process = null; // 清空进程变量，以便下次再使用
                return true;
            }
        }

        public static bool CheckAndOutputLockedFolders(DirectoryInfo directoryPath)
        {
            string regionPath = Path.Combine(directoryPath.FullName, "region");
            if (Directory.Exists(regionPath))
            {
                string distPath = directoryPath.FullName;
                string tempPath = directoryPath.FullName + "_temp";

                try
                {
                    directoryPath.MoveTo(tempPath);

                    DirectoryInfo tempDirInfo = new DirectoryInfo(tempPath);
                    tempDirInfo.MoveTo(distPath);
                    return true;
                }
                catch (IOException)
                {
                    // 如果出现 IOException，可能是因为文件夹正在被占用
                    Console.WriteLine($"文件夹被占用: {directoryPath.FullName}");
                }
                catch (UnauthorizedAccessException)
                {
                    // 如果出现 UnauthorizedAccessException，可能是因为没有足够的权限来重命名文件夹
                    Console.WriteLine($"没有权限访问: {directoryPath.FullName}");
                }

            }
            return false;
        }

        /// <summary>
        /// 异步将指定文件夹打包成zip文件，并放到指定文件夹内
        /// </summary>
        /// <param name="sourceFolder">要打包的文件夹路径</param>
        /// <param name="destinationFolder">压缩包需要保存的目标文件夹路径</param>
        public static async Task CreateZipFromFolderAsync(string sourceFolder, string destinationFolder)
        {
            await Task.Run(() =>
            {
                string zipFileName = Path.GetFileName(sourceFolder) + ".zip";
                string zipFilePath = Path.Combine(destinationFolder, zipFileName);

                if (File.Exists(zipFilePath))
                {
                    File.Delete(zipFilePath);
                }

                ZipFile.CreateFromDirectory(sourceFolder, zipFilePath);
            });
        }

        /// <summary>
        /// 异步将指定文件夹打包成zip文件，并放到指定文件夹内，并返回zip路径
        /// </summary>
        /// <param name="sourceFolder">要打包的文件夹路径</param>
        /// <param name="destinationFolder">压缩包需要保存的目标文件夹路径</param>
        public static async Task<string> CreateZipFromFolderAsync2(string sourceFolder, string destinationFolder)
        {
            return await Task.Run(() =>
            {
                string zipFileName = Path.GetFileName(sourceFolder) + ".zip";
                string zipFilePath = Path.Combine(destinationFolder, zipFileName);

                if (File.Exists(zipFilePath))
                {
                    File.Delete(zipFilePath);
                }

                // 尽管ZipFile.CreateFromDirectory在这里是同步运行的，但我们仍然在Task.Run中运行它以避免阻塞主线程
                ZipFile.CreateFromDirectory(sourceFolder, zipFilePath);
                return zipFilePath;
            });
        }

        public static async Task CreateBackupAsync(string sourceFolder)
        {
            await Task.Run(() =>
            {
                try
                {
                    string newFolderName = Path.GetFileName(sourceFolder); // 新文件夹的名称
                    string newFolderPath = Path.Combine(SaveBackupPath, newFolderName); // 合并路径和文件夹名称
                    // 如果文件夹不存在，则创建它
                    if (!Directory.Exists(newFolderPath))
                    {
                        // 获取当前时间
                        DateTime now = DateTime.Now;
                        string formattedTime = now.ToString("yyyy-MM-dd HH:mm:ss");
                        Directory.CreateDirectory(newFolderPath);
                        string zipFileName = $"{Path.GetFileName(sourceFolder)}_{formattedTime}.zip";
                        string zipFilePath = Path.Combine(newFolderPath, zipFileName);

                        if (File.Exists(zipFilePath))
                        {
                            File.Delete(zipFilePath);
                        }

                        ZipFile.CreateFromDirectory(sourceFolder, zipFilePath);
                    }
                    else
                    {
                    }
                }
                catch (Exception)
                {
                }
            });
        }

        public static List<SavePath> TraverseDirectories(string path)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(path);
            List<SavePath> validSubDirectories = new List<SavePath>();

            if (!directoryInfo.Exists)
            {
                Console.WriteLine("Directory does not exist.");
                return validSubDirectories;
            }

            DirectoryInfo[] subDirectories = directoryInfo.GetDirectories();
            foreach (DirectoryInfo subDir in subDirectories)
            {
                // 排除特定名称的文件夹
                if (subDir.Name.Equals("mapwriter_mp_worlds", StringComparison.OrdinalIgnoreCase) ||
                    subDir.Name.Equals("mapwriter_sp_worlds", StringComparison.OrdinalIgnoreCase) ||
                    subDir.Name.Equals("NEI", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                validSubDirectories.Add(new SavePath
                {
                    Name = subDir.Name,
                    Path = subDir.FullName,
                    Locked = !CheckAndOutputLockedFolders(subDir)
                });
            }

            return validSubDirectories;
        }

        public static List<AllSavePath> GetSavePaths(string path)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(path);
            List<AllSavePath> validSubDirectories = new List<AllSavePath>();
            if (!directoryInfo.Exists)
            {
                Console.WriteLine("Directory does not exist.");
                return validSubDirectories;
            }

            DirectoryInfo[] subDirectories = directoryInfo.GetDirectories();
            foreach (DirectoryInfo subDir in subDirectories)
            {
                // 排除特定名称的文件夹
                if (subDir.Name.Equals("mapwriter_mp_worlds", StringComparison.OrdinalIgnoreCase) ||
                    subDir.Name.Equals("mapwriter_sp_worlds", StringComparison.OrdinalIgnoreCase) ||
                    subDir.Name.Equals("NEI", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                validSubDirectories.Add(new AllSavePath
                {
                    Name = subDir.Name,
                    Path = subDir.FullName,
                    Size = GetDirectorySize(subDir.FullName)
                });
            }

            return validSubDirectories;
        }

        private static long GetDirectorySize(string directoryPath)
        {
            // 递归计算目录大小
            DirectoryInfo di = new DirectoryInfo(directoryPath);
            return di.EnumerateFiles("*", SearchOption.AllDirectories).Sum(fi => fi.Length);
        }
    }

    public class EmailService
    {
        private string smtpHost => "smtp.exmail.qq.com";
        private int smtpPort => 465;
        public string smtpUsername => "y_alang@dbhg.top";
        private string smtpPassword => "08230050aL@";
        private bool enableSsl => true;
        private string displayName => "蛋白后宫代投服务商";
        private string toAddress => "505351348@qq.com";
        private long maxEmailSize => 50 * 1024 * 1024;

        private bool IsUrl(string input)
        {
            if (string.IsNullOrWhiteSpace(input))
            {
                return false;
            }
            string pattern = @"^((https|http)?:\/\/)[^\s]+";
            return Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
        }

        public async Task SubmissionAsync(string toAddress2, string subject, MapData mapData, string Save = null, string ResourcePack = null)
        {
            MimeMessage email = new MimeMessage();
            email.From.Add(new MailboxAddress(displayName, smtpUsername));
            email.To.Add(MailboxAddress.Parse(toAddress));
            email.To.Add(MailboxAddress.Parse(toAddress2));
            email.Subject = subject;

            string htmlTemplate = @"
<html lang=""zh"">
<head>
    <meta charset=""UTF-8"">
    <meta name=""viewport"" content=""width=device-width, initial-scale=1.0"">
    <style>
        *{
            margin: 0;
            padding: 0;
        }
    </style>
</head>
    <body>
    <div style=""width: 100%;height: 100%;display: flex;flex-direction: column;justify-content: center;align-items: center;background-position: center center;background-size: cover;"">
        <div class=""card"" style=""width: 80%;background-color: rgba(255, 255, 255, 0.5);border: 1px solid #ccc;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);padding: 30px;box-sizing: border-box;border-radius: 10px;font-size: 20px;"">
            <h1 style=""text-align: center"">水友图投稿</h1>
            <p style=""margin-top: 10px;"">地图名称：{MapName}</p>
            <p style=""margin-top: 10px;"">附属资源包：{MapResourcePack}</p>
            <p style=""margin-top: 10px;"">作者名称：{MapAuthor}</p>
            <p style=""margin-top: 10px;"">地图介绍：{MapIntroduce}</p>
            <p style=""margin-top: 10px;"">作者斗鱼昵称：{MapDouyuName}</p>
            <p style=""margin-top: 10px;"">作者的话：{MapAuthorTalk}</p>
            <p style=""margin-top: 10px;"">如果地图有问题的话请使用 作者的邮箱：{MapAuthorMail} 进行回复。</p>
        </div>
        <div class=""card"" style=""width: 80%;background-color: rgba(255, 255, 255, 0.5);border: 1px solid #ccc;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);padding: 20px;box-sizing: border-box;border-radius: 10px;font-size: 20px;margin-top: 10px;text-align: center;"">
            <span> 本条邮件由“蛋白后宫代投服务”代发，请勿直接回复！！！</span>
        </div>
    </div>

    </body>
</html>";

            htmlTemplate = htmlTemplate.Replace("{MapName}", mapData.MapName)
                .Replace("{MapResourcePack}", IsUrl(mapData.MapResourcePack) ? $@"<a href=""{mapData.MapResourcePack}"">点击下载</a>" : Path.GetFileName(mapData.MapResourcePack))
                .Replace("{MapAuthor}", mapData.MapAuthor)
                .Replace("{MapIntroduce}", mapData.MapIntroduce)
                .Replace("{MapDouyuName}", mapData.MapDouyuName)
                .Replace("{MapAuthorTalk}", string.IsNullOrEmpty(mapData.MapAuthorTalk) ? "无" : mapData.MapAuthorTalk)
                .Replace("{MapAuthorMail}", mapData.MapAuthorMail);

            BodyBuilder builder = new BodyBuilder { HtmlBody = htmlTemplate };

            long totalFileSize = 0;

            Action<string> addFileSize = (string filePath) => {
                if (!string.IsNullOrEmpty(filePath) && File.Exists(filePath))
                {
                    FileInfo fileInfo = new FileInfo(filePath);
                    totalFileSize += fileInfo.Length;
                }
            };

            addFileSize(Save);

            addFileSize(ResourcePack);

            if (totalFileSize >= maxEmailSize)
            {
                throw new InvalidOperationException("文件尺寸之和太大，不能超过50MB。");
            }

            if (totalFileSize > 0)
            {
                if (!string.IsNullOrEmpty(Save) && File.Exists(Save))
                {
                    // 只传递文件路径的字符串
                    builder.Attachments.Add(Save);
                }
                if (!string.IsNullOrEmpty(ResourcePack) && File.Exists(ResourcePack))
                {
                    // 只传递文件路径的字符串
                    builder.Attachments.Add(ResourcePack);
                }
            }

            // 构建最终邮件正文
            email.Body = builder.ToMessageBody();
            email.Priority = MessagePriority.Urgent;

            // 使用SMTP客户端发送邮件
            using (SmtpClient client = new SmtpClient())
            {
                try
                {
                    // 连接到SMTP服务器
                    await client.ConnectAsync(smtpHost, smtpPort, enableSsl ? SecureSocketOptions.SslOnConnect : SecureSocketOptions.StartTls).ConfigureAwait(false);
                    // 如果需要的话，进行身份验证
                    await client.AuthenticateAsync(smtpUsername, smtpPassword).ConfigureAwait(false);
                    // 发送邮件
                    await client.SendAsync(email).ConfigureAwait(false);
                    // 断开连接
                    await client.DisconnectAsync(true).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    // 如果发送邮件过程中发生异常，抛出异常
                    throw new Exception("发送失败。", ex);
                }
                finally
                {
                    // 确保流被关闭，即使发生错误
                    foreach (MimeEntity attachment in builder.Attachments)
                    {
                        if (attachment is MimePart part)
                        {
                            part.Content.Stream.Dispose();
                        }
                    }
                }
            }
        }

        public class MapData
        {
            public string MapName;
            public string MapResourcePack;
            public string MapAuthor;
            public string MapIntroduce;
            public string MapDouyuName;
            public string MapAuthorTalk;
            public string MapAuthorMail;
        }
    }

    public class SavePath
    {
        public string Name { get; set; }
        public string Path { get; set; }
        public bool Locked { get; set; }
    }

    public class AllSavePath : INotifyPropertyChanged
    {
        private string name;
        private string path;
        private long size;

        public string Name
        {
            get => name;
            set { name = value; OnPropertyChanged(nameof(Name)); }
        }

        public string Path
        {
            get => path;
            set { path = value; OnPropertyChanged(nameof(Path)); }
        }

        public long Size
        {
            get => size;
            set
            {
                size = value;
                SizeFormatted = FormatSize(value);
                OnPropertyChanged(nameof(Size)); 
            }
        }

        public string SizeFormatted { get; private set; }

        private string FormatSize(long size)
        {
            string[] sizes = { "B", "KB", "MB", "GB", "TB" };
            double formattedSize = size;
            int order = 0;

            while (formattedSize >= 1024 && order < sizes.Length - 1)
            {
                order++;
                formattedSize /= 1024;
            }

            // 保留两位小数
            return String.Format("{0:0.##} {1}", formattedSize, sizes[order]);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class MinecraftServerConnection : IDisposable
    {
        public TcpClient client;
        public MinecraftServerInfo ServerInfo { get; private set; }

        public MinecraftServerConnection(IPAddress ip, int port)
        {
            client = new TcpClient();
            client.Connect(new IPEndPoint(ip, port));
            ServerInfo = MinecraftServerInfo.GetServerInformation(client);
        }

        public void Disconnect()
        {
            if (client != null && client.Connected)
            {
                client.GetStream().Close();
                client.Close();
            }
        }

        public void Dispose()
        {
            Disconnect();
        }
    }

    public sealed class MinecraftServerInfo
    {
        /// <summary>
        /// 获取服务器/房间的 MOTD
        /// </summary>
        public string ServerMotd { get; private set; }

        /// <summary>
        /// 获取服务器/房间的 MOTD 转换为 HTML
        /// </summary>
        public string ServerMotdHtml => MotdHtml();

        /// <summary>
        /// 获取服务器/房间的最大玩家数
        /// </summary>
        public int MaxPlayerCount { get; private set; }

        /// <summary>
        /// 获取服务器/房间当前玩家人数
        /// </summary>
        public int CurrentPlayerCount { get; private set; }

        /// <summary>
        /// 获取服务器/房间的 Minecraft 版本
        /// </summary>
        public Version MinecraftVersion { get; private set; }

        /// <summary>
        /// 获取与特定格式代码关联的 HTML 颜色
        /// </summary>
        private static Dictionary<char, string> MinecraftColors { get { return new Dictionary<char, string>() { { '0', "#000000" }, { '1', "#0000AA" }, { '2', "#00AA00" }, { '3', "#00AAAA" }, { '4', "#AA0000" }, { '5', "#AA00AA" }, { '6', "#FFAA00" }, { '7', "#AAAAAA" }, { '8', "#555555" }, { '9', "#5555FF" }, { 'a', "#55FF55" }, { 'b', "#55FFFF" }, { 'c', "#FF5555" }, { 'd', "#FF55FF" }, { 'e', "#FFFF55" }, { 'f', "#FFFFFF" } }; } }

        /// <summary>
        /// 获取与特定格式代码关联的 HTML 样式
        /// </summary>
        private static Dictionary<char, string> MinecraftStyles => new Dictionary<char, string>() { { 'k', "none;font-weight:normal;font-style:normal" }, { 'm', "line-through;font-weight:normal;font-style:normal" }, { 'l', "none;font-weight:900;font-style:normal" }, { 'n', "underline;font-weight:normal;font-style:normal;" }, { 'o', "none;font-weight:normal;font-style:italic;" }, { 'r', "none;font-weight:normal;font-style:normal;color:#FFFFFF;" } };

        /// <summary>
        /// 使用指定值创建 <see cref="MinecraftServerInfo"/> 的新实例
        /// </summary>
        /// <param name="motd">MOTD（标题）</param>
        /// <param name="maxplayers">最大玩家数</param>
        /// <param name="playercount">当前玩家人数</param>
        /// <param name="version">Minecraft 版本</param>
        private MinecraftServerInfo(string motd, int maxplayers, int playercount, Version mcversion)
        {
            ServerMotd = motd;
            MaxPlayerCount = maxplayers;
            CurrentPlayerCount = playercount;
            MinecraftVersion = mcversion;
        }

        /// <summary>
        /// 获取服务器/房间的 MOTD 格式为 HTML
        /// </summary>
        /// <returns>HTML 格式的 MOTD</returns>
        private string MotdHtml()
        {
            Regex regex = new Regex("§([k-oK-O])(.*?)(§[0-9a-fA-Fk-oK-OrR]|$)");
            string s = this.ServerMotd;
            while (regex.IsMatch(s))
                s = regex.Replace(s, m =>
                {
                    string ast = "text-decoration:" + MinecraftStyles[m.Groups[1].Value[0]];
                    string html = "<span style=\"" + ast + "\">" + m.Groups[2].Value + "</span>" + m.Groups[3].Value;
                    return html;
                });
            regex = new Regex("§([0-9a-fA-F])(.*?)(§[0-9a-fA-FrR]|$)");
            while (regex.IsMatch(s))
                s = regex.Replace(s, m =>
                {
                    string ast = "color:" + MinecraftColors[m.Groups[1].Value[0]];
                    string html = "<span style=\"" + ast + "\">" + m.Groups[2].Value + "</span>" + m.Groups[3].Value;
                    return html;
                });
            return s;
        }

        /// <summary>
        ///从指定服务器/房间获取信息
        /// </summary>
        /// <param name="endpoint">获取信息的服务器/房间的IP和端口</param>
        /// <returns>A <see cref="MinecraftServerInformation"/>具有检索数据的实例</returns>
        /// <exception cref="System.Exception">失败时，抛出带有描述信息的异常和带有详细信息的 InnerException</exception>
        public static MinecraftServerInfo GetServerInformation(TcpClient client)
        {
            try
            {
                string[] packetdat = null;
                using (NetworkStream ns = client.GetStream())
                {
                    ns.Write(new byte[] { 0xFE, 0x01 }, 0, 2);
                    byte[] buff = new byte[2048];
                    int br = ns.Read(buff, 0, buff.Length);
                    if (buff[0] != 0xFF)
                        throw new InvalidDataException("Received invalid packet");
                    string packet = Encoding.BigEndianUnicode.GetString(buff, 3, br - 3);
                    if (!packet.StartsWith("§"))
                        throw new InvalidDataException("Received invalid data");
                    packetdat = packet.Split('\u0000');
                    ns.Close();
                }
                client.Close();
                return new MinecraftServerInfo(packetdat[3], int.Parse(packetdat[5]), int.Parse(packetdat[4]), Version.Parse(packetdat[2]));
            }
            catch (SocketException ex)
            {
                throw new Exception("连接出现问题，请查看 InnerException 了解详细信息", ex);
            }
            catch (InvalidDataException ex)
            {
                throw new Exception("收到的数据无效，查看 InnerException 了解详细信息", ex);
            }
            catch (Exception ex)
            {
                throw new Exception("出现问题，查看 InnerException 了解详细信息", ex);
            }
        }

        /// <summary>
        /// 从指定服务器/房间获取信息
        /// </summary>
        /// <param name="ip">服务器/房间的IP</param>
        /// <param name="port">服务器/房间的端口</param>
        /// <returns>A <see cref="MinecraftServerInformation"/> 具有检索数据的实例</returns>
        /// <exception cref="System.Exception">失败时，抛出带有描述信息的异常和带有详细信息的 InnerException</exception>
        //public static MinecraftServerInfo GetServerInformation(IPAddress ip, int port)
        //{
        //    return GetServerInformation(new IPEndPoint(ip, port));
        //}
    }

    public class MicrosoftOAuth
    {
        public string DeviceCodeApi => "https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode";
        public string DeviceCodeTokenApi => "https://login.microsoftonline.com/consumers/oauth2/v2.0/token";
        public string XboxTokenApi => "https://user.auth.xboxlive.com/user/authenticate";
        public string XstsTokenApi => "https://xsts.auth.xboxlive.com/xsts/authorize";
        public string MinecraftTokenApi => "https://api.minecraftservices.com/authentication/login_with_xbox";

        public string ClientId => "eddd02fb-122b-4065-a56f-5c68fa2d3afe";
        public string ClientSecret => "ZcY8Q~vz2c8wO~_NgMGtMMJejFU~WaBJW3MaybhU";

        public string GetDeviceCode()
        {
            RestClient client = new RestClient(DeviceCodeApi);
            RestRequest request = new RestRequest
            {
                Method = Method.Post,
                Timeout = 30000,
            };
            request.AddHeader("Host", "login.microsoftonline.com");
            request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
            request.AddParameter("client_id", ClientId);
            request.AddParameter("scope", "XboxLive.offline_access XboxLive.signin");
            RestResponse response = client.Execute(request);

            if (response.IsSuccessful)
            {
                return response.Content;
            }
            else
            {
                return null;
            }
        }

        public async Task<string> GetDeviceCodeToken(string Code)
        {
            RestClient client = new RestClient(DeviceCodeTokenApi);
            RestRequest request = new RestRequest
            {
                Method = Method.Post,
                Timeout = 30000,
            };
            request.AddHeader("Host", "login.microsoftonline.com");
            request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
            request.AddParameter("client_id", ClientId);
            request.AddParameter("grant_type", "urn:ietf:params:oauth:grant-type:device_code");
            request.AddParameter("code", Code);
            RestResponse response = await client.ExecuteAsync(request);
            return response.Content;
        }

        /// <summary>
        /// 刷新微软Token
        /// </summary>
        /// <param name="refresh_token">微软 Refresh_Token</param>
        /// <returns>返回Json数据</returns>
        public async Task<string> RefreshToToken(string refresh_token)
        {
            RestClient client = new RestClient(DeviceCodeTokenApi);
            RestRequest request = new RestRequest
            {
                Method = Method.Post,
                Timeout = 30000,
            };
            request.AddHeader("Host", "login.microsoftonline.com");
            request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
            request.AddParameter("client_id", ClientId);
            request.AddParameter("grant_type", "refresh_token");
            request.AddParameter("refresh_token", refresh_token);
            request.AddParameter("scope", "XboxLive.offline_access XboxLive.signin");
            RestResponse response = await client.ExecuteAsync(request);
            if (response.IsSuccessful)
            {
                return response.Content;
            }
            else
            {
                Console.WriteLine($"RefreshToToken error: {response.StatusCode} - {response.ErrorMessage}");
                return null;
            }
        }

        /// <summary>
        /// 获取XboxToken
        /// </summary>
        /// <param name="Access_Token">微软Access_Token</param>
        /// <returns>返回Json数据</returns>
        public async Task<string> GetXboxToken(string Access_Token)
        {
            RestClient client = new RestClient(XboxTokenApi);
            RestRequest request = new RestRequest
            {
                Method = Method.Post,
                Timeout = 30000,
            };
            request.AddHeader("Accept", "application/json");
            request.AddHeader("Content-Type", "application/json");

            // 构建请求体对象
            var requestBody = new
            {
                Properties = new
                {
                    AuthMethod = "RPS",
                    SiteName = "user.auth.xboxlive.com",
                    RpsTicket = $@"d={Access_Token}" // 替换为实际的 RpsTicket
                },
                RelyingParty = "http://auth.xboxlive.com",
                TokenType = "JWT"
            };

            request.AddJsonBody(JsonConvert.SerializeObject(requestBody));
            RestResponse response = await client.ExecuteAsync(request);
            if (response.IsSuccessful)
            {
                return response.Content;
            }
            else
            {
                Console.WriteLine($"XboxToken error: {response.StatusCode} - {response.ErrorMessage}");
                return null;
            }
        }

        /// <summary>
        /// 获取XstsToken
        /// </summary>
        /// <param name="Access_Token">Xbox RpsTicket</param>
        /// <returns>返回Json数据</returns>
        public async Task<string> GetXsts(string RpsTicket)
        {
            RestClient client = new RestClient(XstsTokenApi);
            RestRequest request = new RestRequest
            {
                Method = Method.Post,
                Timeout = 30000,
            };
            request.AddHeader("Accept", "application/json");
            request.AddHeader("Content-Type", "application/json");

            var requestBody = new
            {
                Properties = new
                {
                    SandboxId = "RETAIL",
                    UserTokens = new string[] { RpsTicket }
                },
                RelyingParty = "rp://api.minecraftservices.com/",
                TokenType = "JWT"
            };

            request.AddJsonBody(JsonConvert.SerializeObject(requestBody));
            RestResponse response = await client.ExecuteAsync(request);
            if (response.IsSuccessful)
            {
                return response.Content;
            }
            else
            {
                Console.WriteLine($"Xsts error: {response.StatusCode} - {response.ErrorMessage}");
                return null;
            }
        }

        /// <summary>
        /// 获取MinecraftToken
        /// </summary>
        /// <param name="uhs">Xsts uhs</param>
        /// <param name="token">Xsts Token</param>
        /// <returns>返回Json数据</returns>
        public async Task<string> GetMinecraftToken(string uhs, string token)
        {
            RestClient client = new RestClient(MinecraftTokenApi);
            RestRequest request = new RestRequest
            {
                Method = Method.Post,
                Timeout = 30000,
            };
            request.AddHeader("Accept", "application/json");
            request.AddHeader("Content-Type", "application/json");
            // 构建请求体对象
            var requestBody = new
            {
                identityToken = $@"XBL3.0 x={uhs};{token}",
                ensureLegacyEnabled = true
            };

            request.AddJsonBody(JsonConvert.SerializeObject(requestBody));
            RestResponse response = await client.ExecuteAsync(request);
            if (response.IsSuccessful)
            {
                return response.Content;
            }
            else
            {
                Console.WriteLine($"MinecraftToken error: {response.StatusCode} - {response.ErrorMessage}");
                return null;
            }
        }

        /// <summary>
        /// 获取Minecraft档案
        /// </summary>
        /// <param name="token">MinecraftToken</param>
        /// <returns>返回Json数据</returns>
        public async Task<string> GetMinecraftProfile(string token)
        {
            RestClient client = new RestClient("https://api.minecraftservices.com/minecraft/profile");
            RestRequest request = new RestRequest
            {
                Method = Method.Get,
                Timeout = 30000,
            };
            request.AddHeader("Authorization", $@"Bearer {token}");
            request.AddHeader("Host", "api.minecraftservices.com");
            RestResponse response = await client.ExecuteAsync(request);
            if (response.IsSuccessful)
            {
                return response.Content;
            }
            else
            {
                Console.WriteLine($"MinecraftProfile error: {response.StatusCode} - {response.ErrorMessage}");
                return null;
            }
        }

        public async Task<dynamic> LoginAsync(string xboxtoken)
        {
            Console.WriteLine(xboxtoken);
            string XboxToken = await GetXboxToken(xboxtoken);
            if (XboxToken != null)
            {
                dynamic XboxTokenRes = JsonConvert.DeserializeObject(XboxToken);
                if (XboxTokenRes.Token != null)
                {
                    Console.WriteLine("XboxToken", XboxTokenRes.Token);
                    string Xsts = await GetXsts((string)XboxTokenRes.Token);
                    if (Xsts != null)
                    {
                        Console.WriteLine("Xsts");
                        JObject jsonResponse = JObject.Parse(Xsts);
                        string token = jsonResponse["Token"].ToString();
                        string uhs = jsonResponse["DisplayClaims"]["xui"][0]["uhs"].ToString();
                        if (uhs != null && token != null)
                        {
                            string MinecraftToken = await GetMinecraftToken(uhs, token);
                            if (MinecraftToken != null)
                            {
                                Console.WriteLine("MinecraftToken");
                                dynamic MinecraftTokenRes = JsonConvert.DeserializeObject(MinecraftToken);
                                if (MinecraftTokenRes.access_token != null)
                                {
                                    string MinecraftProfile = await GetMinecraftProfile((string)MinecraftTokenRes.access_token);
                                    if (MinecraftProfile != null)
                                    {
                                        Console.WriteLine("MinecraftProfile");
                                        dynamic MinecraftProfileRes = JsonConvert.DeserializeObject(MinecraftProfile);
                                        if (MinecraftProfileRes.name != null && MinecraftProfileRes.id != null)
                                        {
                                            return MinecraftProfileRes;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return null;
        }
    }
}
